<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="sHZ58" id="sHZ58"><span data-lake-id="u7e43b41f" id="u7e43b41f">典型回答</span></h1>
  <p data-lake-id="ua5b72924" id="ua5b72924"><span data-lake-id="ubc81cdb4" id="ubc81cdb4">反射机制指的是程序在</span><strong><span data-lake-id="ua1b34bb4" id="ua1b34bb4">运行时</span></strong><span data-lake-id="u3be771cc" id="u3be771cc">能够获取自身的信息。在java中，只要给定类的名字，那么就可以通过反射机制来获得类的所有属性和方法。 </span></p>
  <p data-lake-id="uf9cdd3c9" id="uf9cdd3c9"><span data-lake-id="u006cee48" id="u006cee48">​</span><br></p>
  <p data-lake-id="u921c95b1" id="u921c95b1"><span data-lake-id="u4aa033fc" id="u4aa033fc">Java的反射可以：</span></p>
  <ol list="uf750ccd7">
   <li fid="u9beed946" data-lake-id="uf28f74a3" id="uf28f74a3"><span data-lake-id="uaeb11c74" id="uaeb11c74" style="color: rgb(38, 38, 38)">在运行时判断任意一个对象所属的类。</span></li>
   <li fid="u9beed946" data-lake-id="uccdfaa28" id="uccdfaa28"><span data-lake-id="u5dc6b094" id="u5dc6b094" style="color: rgb(38, 38, 38)">在运行时判断任意一个类所具有的成员变量和方法。</span></li>
   <li fid="u9beed946" data-lake-id="u80b07801" id="u80b07801"><span data-lake-id="ua6f25fe5" id="ua6f25fe5" style="color: rgb(38, 38, 38)">在运行时任意调用一个对象的方法</span></li>
   <li fid="u9beed946" data-lake-id="u16b93768" id="u16b93768"><span data-lake-id="ua381170f" id="ua381170f" style="color: rgb(38, 38, 38)">在运行时构造任意一个类的对象</span></li>
  </ol>
  <p data-lake-id="uaf008f53" id="uaf008f53"><span data-lake-id="u65a8734e" id="u65a8734e" style="color: rgb(38, 38, 38)">​</span><br></p>
  <pre lang="java"><code>
Object obj = // ... 任意对象;
Class&lt;?&gt; clazz = obj.getClass();

// 获取成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
    System.out.println("成员变量: " + field.getName());
}

// 获取方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
    System.out.println("方法: " + method.getName());
}


Method method = clazz.getDeclaredMethod("methodName", // 方法参数类型...);
method.setAccessible(true); // 如果方法是私有的
method.invoke(obj, // 方法参数...);


// 默认构造函数
Object obj = clazz.newInstance();

// 或者使用特定的构造函数
Constructor&lt;?&gt; constructor = clazz.getConstructor(// 参数类型...);
Object obj = constructor.newInstance(// 构造函数参数...);

</code></pre>
  <p data-lake-id="ue3e2ba3b" id="ue3e2ba3b"><span data-lake-id="u626819e4" id="u626819e4" style="color: rgb(38, 38, 38)">​</span><br></p>
  <p data-lake-id="u43b5c401" id="u43b5c401"><span data-lake-id="u306b91f8" id="u306b91f8" style="color: rgb(38, 38, 38)">​</span><br></p>
  <p data-lake-id="uc96022ba" id="uc96022ba"><span data-lake-id="u15263005" id="u15263005" style="color: rgb(38, 38, 38)">反射的好处就是可以提升程序的灵活性和扩展性，比较容易在运行期干很多事情。但是他带来的问题更多，主要由以下几个：</span></p>
  <p data-lake-id="uf37df7bc" id="uf37df7bc"><span data-lake-id="u36e29ffa" id="u36e29ffa" style="color: rgb(38, 38, 38)">​</span><br></p>
  <p data-lake-id="ueac97687" id="ueac97687"><span data-lake-id="ud0e207c9" id="ud0e207c9">1、代码可读性低及可维护性</span></p>
  <p data-lake-id="u04d649f6" id="u04d649f6"><span data-lake-id="u295a0e20" id="u295a0e20">2、反射代码执行的性能低</span></p>
  <p data-lake-id="u1b53b158" id="u1b53b158"><span data-lake-id="u39e5d3cd" id="u39e5d3cd">3、反射破坏了封装性</span></p>
  <p data-lake-id="udf648549" id="udf648549"><span data-lake-id="u4a2b2d1b" id="u4a2b2d1b">​</span><br></p>
  <p data-lake-id="uc4a8099e" id="uc4a8099e"><span data-lake-id="u2b6d3a48" id="u2b6d3a48">所以，我们应该在业务代码中应该尽量避免使用反射。但是，作为一个合格的Java开发，也要能读懂中间件、框架中的反射代码。在有些场景下，要知道可以使用反射解决部分问题。</span></p>
  <p data-lake-id="uac022893" id="uac022893"><span data-lake-id="u8b36de6f" id="u8b36de6f">​</span><br></p>
  <p data-lake-id="u147a1663" id="u147a1663"><span data-lake-id="u755d484b" id="u755d484b">那么，反射为什么慢呢？主要由以下几个原因：</span></p>
  <p data-lake-id="ua9df48a1" id="ua9df48a1"><span data-lake-id="u1fea38df" id="u1fea38df">​</span><br></p>
  <p data-lake-id="ue2b0beef" id="ue2b0beef"><span data-lake-id="u94bfea58" id="u94bfea58">1、由于反射涉及动态解析的类型，</span><strong><span data-lake-id="ud961ee5d" id="ud961ee5d">因此不能执行某些Java虚拟机优化</span></strong><span data-lake-id="u655aec6d" id="u655aec6d">，如JIT优化。</span></p>
  <p data-lake-id="u791f8bf3" id="u791f8bf3"><span data-lake-id="uddcf25ca" id="uddcf25ca">​</span><br></p>
  <p data-lake-id="u30b8e248" id="u30b8e248"><span data-lake-id="u8c9099c3" id="u8c9099c3">2、在使用反射时，参数需要包装（</span><strong><span data-lake-id="u8ad00cdc" id="u8ad00cdc">boxing</span></strong><span data-lake-id="ueac410b8" id="ueac410b8">)成Object[] 类型，但是真正方法执行的时候，又需要再拆包（</span><strong><span data-lake-id="u53a1884a" id="u53a1884a">unboxing</span></strong><span data-lake-id="u7a9411f0" id="u7a9411f0">)成真正的类型，这些动作不仅消耗时间，而且过程中也会产生很多对象，对象一多就容易导致GC，GC也会导致应用变慢。</span></p>
  <p data-lake-id="u3a745dac" id="u3a745dac"><span data-lake-id="u77252f7b" id="u77252f7b">​</span><br></p>
  <p data-lake-id="ub5ab6165" id="ub5ab6165"><span data-lake-id="ub6860872" id="ub6860872">3、反射调用方法时会从方法数组中遍历查找，并且会检查可见性。这些动作都是耗时的。</span></p>
  <p data-lake-id="ue7b1f022" id="ue7b1f022"><span data-lake-id="u175cc79e" id="u175cc79e">​</span><br></p>
  <p data-lake-id="ue12ae39a" id="ue12ae39a"><span data-lake-id="u62eb4139" id="u62eb4139">4、不仅方法的可见性要做检查，参数也需要做很多额外的检查。</span></p>
  <p data-lake-id="ub02f251d" id="ub02f251d"><br></p>
  <h1 data-lake-id="Qb14s" id="Qb14s"><span data-lake-id="ucff0c055" id="ucff0c055" style="color: rgb(38, 38, 38)">扩展知识</span></h1>
  <p data-lake-id="u47cbf4ad" id="u47cbf4ad"><br></p>
  <h2 data-lake-id="RFnRq" id="RFnRq"><span data-lake-id="ub7da0c25" id="ub7da0c25">反射常见的应用场景</span></h2>
  <ol list="u83a32660">
   <li fid="uc9ae611d" data-lake-id="ua92fbc52" id="ua92fbc52"><span data-lake-id="u191ca8bc" id="u191ca8bc">动态代理</span></li>
   <li fid="uc9ae611d" data-lake-id="u1f6f49df" id="u1f6f49df"><span data-lake-id="ufe0ab888" id="ufe0ab888">JDBC的class.forName</span></li>
   <li fid="uc9ae611d" data-lake-id="ua4f94869" id="ua4f94869"><span data-lake-id="u3c158139" id="u3c158139">BeanUtils中属性值的拷贝</span></li>
   <li fid="uc9ae611d" data-lake-id="u1de7a52a" id="u1de7a52a"><span data-lake-id="u7dedbe34" id="u7dedbe34">RPC框架</span></li>
   <li fid="uc9ae611d" data-lake-id="u792100ae" id="u792100ae"><span data-lake-id="u8c2bc021" id="u8c2bc021">ORM框架</span></li>
   <li fid="uc9ae611d" data-lake-id="ucb6d6824" id="ucb6d6824"><span data-lake-id="u605f335e" id="u605f335e">Spring的IOC/DI</span></li>
  </ol>
  <h2 data-lake-id="GYOcx" id="GYOcx"><span data-lake-id="u8ab8aa12" id="u8ab8aa12">反射和Class的关系</span></h2>
  <p data-lake-id="u24b10ec5" id="u24b10ec5"><span data-lake-id="u92b868a6" id="u92b868a6">Java的Class类是java反射机制的基础,通过Class类我们可以获得关于一个类的相关信息</span></p>
  <p data-lake-id="udee486f0" id="udee486f0"><span data-lake-id="ud917717b" id="ud917717b">Java.lang.Class是一个比较特殊的类，它用于封装被装入到JVM中的类（包括类和接口）的信息。当一个类或接口被装入的JVM时便会产生一个与之关联的java.lang.Class对象，可以通过这个Class对象对被装入类的详细信息进行访问。</span></p>
  <p data-lake-id="u03f79a5b" id="u03f79a5b"><span data-lake-id="uc97747bb" id="uc97747bb">虚拟机为每种类型管理一个独一无二的Class对象。也就是说，每个类（型）都有一个Class对象。运行程序时，Java虚拟机(JVM)首先检查是否所要加载的类对应的Class对象是否已经加载。如果没有加载，JVM就会根据类名查找.class文件，并将其Class对象载入。</span></p>
  <p data-lake-id="u831ae660" id="u831ae660"><span data-lake-id="udea2dd20" id="udea2dd20">​</span><br></p>
  <h2 data-lake-id="GcWYS" id="GcWYS"><span data-lake-id="u0c131973" id="u0c131973">反射破坏单例</span></h2>
  <p data-lake-id="ue78b4202" id="ue78b4202"><br></p>
 </body>
</html>